﻿using System;
using System.IO;
using System.Reflection;
using System.Xml.Linq;
using Microsoft.Office.Interop.Outlook;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Outlook.WorkItems.Extension.Managers;

namespace Outlook.WorkItems.Extension.Manager.TeamProjectManager
{
    /// <summary>
    /// Create Work Item with specified mapping and many options
    /// </summary>
    public class CreateWiAction : IAction<MailItem>
    {
        /// <summary>
        /// Mapping between Wor Item Field and Mail Message Field
        /// </summary>
        public WorkItemMapping Mapping { get; set; }
        /// <summary>
        /// Enable or disable the option of adding mail message attachments to Work Item
        /// </summary>
        public bool AddMessageToAttachmentWi { get; set; }
        /// <summary>
        /// get or set mail format attached to work item
        /// </summary>
        public string FormatMail { get; set; }
        /// <summary>
        /// Enable or disable the option of adding mail message to attachment Work Item
        /// </summary>
        public bool AddMessageAttachments { get; set; }
        /// <summary>
        /// Tracking of messages of one conversation in one work item
        /// </summary>
        public bool TrackConversationInWorkItem { get; set; }

        /// <summary>
        /// Serialize this object in XML 
        /// </summary>
        /// <returns></returns>
        public XNode SerializeAction()
        {
            return new XElement("CreateWIAction",
                        new XAttribute("addMessageToAttachmentWI", AddMessageToAttachmentWi),
                        new XAttribute("formatMail", FormatMail ?? ""),
                        new XAttribute("addMessageAttachments", AddMessageAttachments),
                        new XAttribute("trackConversationInWorkItem", TrackConversationInWorkItem),
                        Mapping.SerializeWorkItemMapping());
        }

        /// <summary>
        /// Deserialize XML in this Object
        /// </summary>
        /// <param name="action"></param>
        public void DeserializeAction(XElement action)
        {
            Mapping = new WorkItemMapping();

            var addMessageAttachmentsAttribute = action.Attribute("addMessageAttachments");
            if (addMessageAttachmentsAttribute != null && addMessageAttachmentsAttribute.Value != null)
                AddMessageAttachments = Convert.ToBoolean(addMessageAttachmentsAttribute.Value);

            var addMessageToAttachmentWiAttribute = action.Attribute("addMessageToAttachmentWI");
            if (addMessageToAttachmentWiAttribute != null && addMessageToAttachmentWiAttribute.Value != null)
                AddMessageToAttachmentWi = Convert.ToBoolean(addMessageToAttachmentWiAttribute.Value);

            var formatMailAttribute = action.Attribute("formatMail");
            if (formatMailAttribute != null && formatMailAttribute.Value != null)
                FormatMail = formatMailAttribute.Value;

            var trackConversationInWorkItemAttribute = action.Attribute("trackConversationInWorkItem");
            if (trackConversationInWorkItemAttribute != null && trackConversationInWorkItemAttribute.Value != null)
                TrackConversationInWorkItem = Convert.ToBoolean(trackConversationInWorkItemAttribute.Value);

            Mapping.DeserializeWorkItemMapping(action.Element("WorkItemMapping"));
        }

        /// <summary>
        /// Execute the action
        /// </summary>
        /// <param name="item"></param>
        public void DoAction(MailItem item)
        {
            if (item == null)
                return;

            var folder = (MAPIFolder)item.Parent;
            if (!TeamProjectLinksManager.ContainsTeamProjectLink(folder.EntryID))
                return;

            var link = TeamProjectLinksManager.GetTeamProjectLink(folder.EntryID);

            var wiStore = TeamProjectLinksManager.GetWorkItemStore(link.TeamServerUri);
            WorkItem wi = null;

            // Track messages of one conversation in one Work Item
            if (TrackConversationInWorkItem)
            {
                var findedMail = folder.Items.Find(string.Format("[ConversationTopic] = '{0}'", item.ConversationTopic.Replace("'", @"''"))) as MailItem;
                var finded = findedMail != null && findedMail.ItemProperties["RelatedWIIds"] != null;
                while (!finded)
                {
                    findedMail = folder.Items.FindNext() as MailItem;
                    finded = (findedMail != null && findedMail.ItemProperties["RelatedWIIds"] != null) || (findedMail == null);
                }
                if (findedMail != null)
                {
                    string relatedWis = findedMail.ItemProperties["RelatedWIIds"].Value.ToString();
                    int wiId;
                    if (int.TryParse(relatedWis, out wiId))
                    {
                        wi = wiStore.GetWorkItem(wiId);
                    }
                }
                else
                {
                    wi = new WorkItem(wiStore.Projects[link.TeamProjectName].WorkItemTypes[Mapping.WorkItemType]);
                }
            }
            else
            {
                wi = new WorkItem(wiStore.Projects[link.TeamProjectName].WorkItemTypes[Mapping.WorkItemType]);
            }

            if (wi == null)
                return;

            // Create Work Item with mapping
            foreach (var field in Mapping.MappingFields)
            {
                if (!string.IsNullOrEmpty(field.MessageFieldName) && item.ItemProperties[field.MessageFieldName].Value != null)
                {
                    if (field.MessageFieldName == "HTMLBody" && (wi.Type.FieldDefinitions[field.WiFieldName].FieldType == FieldType.String || wi.Type.FieldDefinitions[field.WiFieldName].FieldType == FieldType.PlainText))
                    {
                        var filePath = Path.GetTempFileName();
                        item.SaveAs(filePath, OlSaveAsType.olTXT);
                        wi.Fields[field.WiFieldName].Value = File.ReadAllText(filePath);
                    }
                    else if (field.MessageFieldName == "HTMLBody" && wi.Type.FieldDefinitions[field.WiFieldName].FieldType == FieldType.Html)
                        wi.Fields[field.WiFieldName].Value = item.HTMLBody;
                    else
                        wi.Fields[field.WiFieldName].Value = item.ItemProperties[field.MessageFieldName].Value;
                }
                else if (!string.IsNullOrEmpty(field.StaticValue))
                {
                    wi.Fields[field.WiFieldName].Value = field.StaticValue;
                }
            }

            // Add message to work item attachment
            if (AddMessageToAttachmentWi)
            {
                var fileName = item.Subject;
                var regex = new System.Text.RegularExpressions.Regex("[^a-zA-Z0-9]");
                fileName = regex.Replace(fileName, "");

                var format = (OlSaveAsType)Enum.Parse(typeof(OlSaveAsType), FormatMail);
                switch (format)
                {
                    case OlSaveAsType.olHTML:
                        fileName += ".htm";
                        break;
                    case OlSaveAsType.olMHTML:
                        fileName += ".mht";
                        break;
                    case OlSaveAsType.olMSG:
                    case OlSaveAsType.olMSGUnicode:
                        fileName += ".msg";
                        break;
                    case OlSaveAsType.olTXT:
                        fileName += ".txt";
                        break;
                    default:
                        break;
                }

                var path = Path.GetTempPath() + "\\" + fileName;
                item.SaveAs(path, format);
                wi.Attachments.Add(new Microsoft.TeamFoundation.WorkItemTracking.Client.Attachment(path, null));
            }

            // Add Message attachments to Work Item attachments
            if (AddMessageAttachments && item.Attachments.Count > 0)
            {
                foreach (Microsoft.Office.Interop.Outlook.Attachment att in item.Attachments)
                {
                    var appDataFolder = Path.GetTempPath();
                    var path = appDataFolder + "\\" + att.FileName;
                    att.SaveAsFile(path);
                    wi.Attachments.Add(new Microsoft.TeamFoundation.WorkItemTracking.Client.Attachment(path, null));
                }
            }
            wi.Save();

            var relatedWorkItemsId = item.ItemProperties["RelatedWIIds"];

            // Add Work Item Identifier to Item Properties of message
            if (relatedWorkItemsId == null)
            {
                item.ItemProperties.Add("RelatedWIIds", OlUserPropertyType.olText, false, Missing.Value);
                relatedWorkItemsId = item.ItemProperties["RelatedWIIds"];
                relatedWorkItemsId.Value = "";
            }

            relatedWorkItemsId.Value = wi.Id;
            item.Save();


        }
    }

    public static class HtmlHelper
    {
        public static string StripTags(string html)
        {

            // Removes tags from passed HTML            
            var objRegEx = new System.Text.RegularExpressions.Regex("<[^>]*>");

            var retValue = objRegEx.Replace(html, "");
            return System.Web.HttpUtility.HtmlDecode(retValue);
        }
    }
}
